package org.dfl.plugin.editor.markers;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dfl.plugin.editor.model.ModelElement;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;

/**
 * static marker manager
 * All MarkersContainers are suposed to register in this GlobalMarkersManager in the constructor and 
 * unregister themselfs when removed from model
 * 
 * this class listen for selection changes in a problem view to focus selected object on diagram
 * @author Piotr Wlodarczyk
 */
public class GlobalMarkersManager extends Action implements IWorkbenchWindowActionDelegate {
	private static Logger logger = Logger.getLogger(GlobalMarkersManager.class);
	
	// markersContianers are assigned to IResource 
	private static Map<IResource, Set<ResourceMarkersContainer>> markers = new HashMap<IResource, Set<ResourceMarkersContainer>>();

	/**
	 * register one markersContainer - the resource is extracted from the container 
	 * @param container
	 */
	public static void registerMarkersContainer(ResourceMarkersContainer container) {
		IResource r = container.getResource();

		if (!markers.containsKey(r)) {
			markers.put(r, new HashSet<ResourceMarkersContainer>());

			int depth = IResource.DEPTH_INFINITE;
			try {
				r.deleteMarkers(IMarker.PROBLEM, true, depth);
			} catch (CoreException e) {
				logger.error(e.getMessage(), e);
			}
		}

		markers.get(r).add(container);
	}

	/**
	 * unregister specific markersContainer
	 * @param container
	 */
	public static void unregisterMarkersContainer(ResourceMarkersContainer container) {
		IResource r = container.getResource();
		container.clearMarkers();

		if (markers.containsKey(r) && markers.get(r).remove(container) && markers.get(r).isEmpty()) {
			markers.remove(r);
		}
	}

	/**
	 * remove all markers for specific resource
	 * @param r - resource
	 */
	public static void unregisterResource(IResource r) {
		if (markers.containsKey(r)) {
			Set<ResourceMarkersContainer> ms = markers.get(r);
			for (ResourceMarkersContainer m : ms) {
				m.clearMarkers();
			}
			markers.remove(r);
		}
	}
	
	@SuppressWarnings("restriction")
	public static Object getOwnerOf(IMarker m){
		IResource resource = m.getResource();
		if(!markers.containsKey(resource)){
			return null;
		}
		
		long id = m.getId();
		Set<ResourceMarkersContainer> toSearch = markers.get(resource);
		for(ResourceMarkersContainer r : toSearch){
			if(r.getMarkers().containsKey(id)){
				return r.getOwner();
			}
		}
		
		return null;
	}
	
	// ------------------------------------------- listener 
	/** Called when the action is created. */
	public void init(IWorkbenchWindow window) {
	}

	/** Called when the action is discarded. */
	public void dispose() {
	}

	/** Called when the action is executed. */
	public void run(IAction action) {
	}

	/** Called when objects in the editor are selected or deselected. */
	@SuppressWarnings("restriction")
	public void selectionChanged(IAction action, ISelection selection) {
		if (selection instanceof StructuredSelection) {
			StructuredSelection sel = (StructuredSelection) selection;
			Object el = sel.getFirstElement();
			if (el instanceof IMarker) {
				IMarker m = (IMarker) el;
				Object res = GlobalMarkersManager.getOwnerOf(m);
				if (res != null && res instanceof ModelElement) {
					((ModelElement) res).focus();
				}
			}
		}
	}
}
